using System;
using System.Collections.Generic;
using System.Reflection;
using ConfOrm;
using ConfOrm.NH;
using ConfOrm.Patterns;
using FluentNHibernate.Automapping;
using FluentNHibernate.Cfg;
using NHibernate;
using NHibernate.Cfg;
using ThunderJob.Domain;
using ThunderJob.Persistence.Extensions;
using ThunderJob.Persistence.Storage;

namespace ThunderJob.Persistence
{
    public enum SessionContext
    {
        Web, Simple
    }

    public class NHibernateSession
    {
        public static Configuration Configuration { get; private set; }

        private static ISessionFactory factory;
        private static bool factoryBuilded;
        private static readonly object sync = new object();
        private static ISessionStorage sessionStorage;

        private void BuildFactory()
        {

            var orm = new ObjectRelationalMapper();
            Type[] entities = new[] { typeof(Anuncio), typeof(Empresa) };
            orm.TablePerClass(entities);
            orm.Patterns.PoidStrategies.Add(new HighLowPoidPattern(new { max_low = 100 }));

            Mapper mapper = new Mapper(orm);
            mapper.AddManyToOnePattern(x => true,
                (mi, mto) => mto.Column(mi.GetPropertyOrFieldType().Name + "Id"));
            mapper.AddCollectionPattern(x => true,
                (mi, c) => c.Key(km => km.Column(mi.DeclaringType.Name + "Id")));

            Configuration.AddHbmMapping(mapper, entities);
            factory = Configuration.BuildSessionFactory();
        }

        private void Configure(string configFile)
        {
            Configuration = new Configuration().Configure(configFile);
        }

        private void CreateSessionStorage(SessionContext context)
        {
            switch (context)
            {
                case SessionContext.Web:
                    sessionStorage = new WebSessionStorage(factory);
                    break;
                case SessionContext.Simple:
                    sessionStorage = new SimpleSessionStorage();
                    break;
            }
        }

        public static void Init(string configFile, SessionContext context)
        {
            if (!factoryBuilded)
            {
                lock (sync)
                {
                    if (!factoryBuilded)
                    {
                        NHibernateSession session = new NHibernateSession();
                        session.Configure(configFile);
                        session.BuildFactory();
                        session.CreateSessionStorage(context);
                        factoryBuilded = true;
                    }
                }
            }
        }

        public static void Reset()
        {
            ISession session = DeleteFromStorage();
            session.Dispose();
            factory.Dispose();
            factoryBuilded = false;
        }

        public static ISession Current
        {
            get
            {
                return sessionStorage.GetSession();
            }
        }

        public static ISession CreateInStorage()
        {
            ISession session = factory.OpenSession();
            sessionStorage.SetSession(session);
            return session;
        }

        public static ISession DeleteFromStorage()
        {
            return sessionStorage.DeleteSession();
        }
    }
}